その他(中級)
![]()
■ インクリメント型エンコーダ読込
<試作品仕様>
・A相とB相からなるインクリメント型エンコーダ出力を読み込む
・C.W.(時計まわり) 、C.C.W.(反時計まわり)の 回転方向はA相パルスの立上りにおけるB相の極性により判別する。
・エンコーダA相からのパルスの数をカウントして液晶に表示する。
・液晶への表示は HEXスイッチの設定値により カウントを逓倍して表示する
| HEXスイッチのメモリ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
| b3 b2 b1 b0 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
| N[倍] | 1 | 10 | 100 | 1000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 | 10000 |
・0.25msec毎にA相の検出をおこない チャタリングが安定したらB相を読み込み回転方向を検出する。
・C.W.(時計まわり)にエンコーダのツマミを回したらカウント数が増加し、 、C.C.W.(反時計まわり)に回したらカウント数は減少すること。
・表示カウント数の最少値は0とする。
<試作品回路図>(→回路図のPDFファイル)
・ dsPIC4013をつかった場合の回路図を以下に示します。
・ エンコーダは秋月電子で販売されている インクリメント型エンコーダ アルファ EC16B (RE16F-40E3-L(A)-24P相当)です。

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

<プログラム例>
//*******************************************************************
// 手動インクリメント型エンコーダ読込
// dsPIC4013
//*******************************************************************
#include <p30f4013.h>
#include <timer.h>
#include <ports.h>
#include "1lcd_lib_C30.h"
#define b0 PORTBbits.RB5
#define b1 PORTBbits.RB4
#define b2 PORTBbits.RB3
#define b3 PORTBbits.RB2
_FOSC(CSW_FSCM_OFF & // クロック切り替えなし、フェールセイフクロックモニタなし
HS2_PLL16 //外部発振子周波数 × postscaler × PLL:16倍 → 10MHz × 1/2 × 16 = 80MHz
);
_FWDT(WDT_OFF); //ウォッチドックタイマ:OFF
_FBORPOR(PBOR_ON & //ブラウンアウトリセット機能:ON
BORV42 & //ブラウンアウト電圧:4.2V
// BORV_42 & //ブラウンアウト電圧:4.2V (旧 config 記載形式)
PWRT_64 & //パワーオンリセットタイマ64msec
MCLR_EN //MCLR機能:ON
);
_FGS(CODE_PROT_OFF); //コードプロテクト:OFF
unsigned char dummy = ' ';
signed long Count = 0; //FF入力周波数(エンコダカウント数 24パルス/回転) 32bit
unsigned int Mag = 1; //エンコーダカウント数の周波数換算倍率
unsigned char AswCount = 0; //A相0検出回数
unsigned char nAswCount = 0; //A相1検出回数
unsigned char Asw;
unsigned char Rising;
char Buf[17]; //文字列のバッファー用レジスタ
void delay_ms(unsigned int N) //1msec遅延関数
{
__delay32(Clock/4000*N); //1msecのウェイト数: 80,000,000/4000 = 20,000
}
void Mag_Func() //エンコーダカウント数−周波数倍率検出 //HEXスイッチ読み込み
{
if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Mag = 1; //0
else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0))Mag = 10; //1
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1))Mag = 100; //2
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0))Mag = 1000; //3
else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1))Mag = 10000; //4
else Mag = 10000; //3
}
void _ISR _T1Interrupt(void) //液晶表示
{
IFS0bits.T1IF = 0; //IFS0レジスタの T1IF(タイマ2の割込み検出)フラグリセット
lcd_clear(); // 全消去
sprintf(Buf,"Count=%ld",Count);//arguementがないと遅い C30のバグ?
lcd_str(Buf);
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf,"*%u(multiply)",Mag); //文字列としてバッファーに収納
lcd_str(Buf);
}
void Encode() //エンコーダ読み込み
{
Mag_Func(); //エンコーダ倍率
if(PORTAbits.RA11 == 0) AswCount++; //A相検出値が0なら AswCountをインクリメント
else AswCount = 0;
if(AswCount >= 8)
{
Asw = 0; //AswCount = 8 の時 A相は0である。
AswCount = 8;
}
if(PORTAbits.RA11 == 1)nAswCount++; //A相検出値が1なら nAswCountをインクリメント
else nAswCount = 0;
if(nAswCount >= 8)
{
if(Asw == 0)Rising = 1; //A相のパルスの立上り検出
Asw = 1; //nAswCount = 8 の時 A相は0である。
nAswCount = 8;
}
if(Rising == 1) //A相パルスが立上った場合
{
Rising = 0;
if(PORTDbits.RD9 == 0)
{
Count = Count + Mag; //C.W.の場合
if(Count >= 1000000)Count = 1000000; //最大 1000000
}
else
{
Count = Count - Mag; //C.C.W.の場合
if(Count <= 0) Count = 0;
}
}
__delay32(5000); //0.25msec(読み込み)
}
int main(void)
{
TRISA = 0xFFFF;
ADPCFG = 0xFFFF; //デジタルポートに設定
TRISB = 0x003C; //
TRISD = 0x0200; //RD9: in
TRISF = 0;
LATFbits.LATF4 = 1; //JK FF Q1 Clear Port → 1
LATFbits.LATF5 = 1; //JK FF Q2 Clear Port → 1
//T1タイマ 液晶表示
OpenTimer1(
T1_ON & //タイマ1:ON
T1_GATE_OFF & //ゲート制御(信号がある時だけタイマが動作)OFF
T1_PS_1_256 & //プリスケーラ
T1_SYNC_EXT_OFF & //外部同期タイマはタイマ1のみ
T1_SOURCE_INT,
23438 //300msec / 0.05μsec / 256 = 23437.5
);
lcd_init(); // LCD初期化
lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF
lcd_clear(); // 全消去
sprintf(Buf,"Encoder %c",dummy);//arguementがないと遅い C30のバグ?
lcd_str(Buf);
//液晶表示
lcd_cmd(0xC0); //2目表示行目の先頭へ
sprintf(Buf,"Start !! %c",dummy); //文字列としてバッファーに収納
lcd_str(Buf); // 開始メッセージ2行
delay_ms(1000);
ConfigIntTimer1(T1_INT_PRIOR_2 & T1_INT_ON ); //割込みレベル2 連結タイマ1割込みON
EnableIntT1;
//割込み許可
while(1)
{
Encode();
}
return 0;
}
//*************************************************************************
//インクルードファイル 1lcd_lib_C30.h
//このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、
//C30コンパイラ対応等でに変更したものです。
//*************************************************************************
#include "p30f4013.h"
#define Clock 80000000 // 単位はHzで指定
// LCDポート設定
#define lcd_port_DB7 LATBbits.LATB12 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB6 LATBbits.LATB11 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB5 LATBbits.LATB10 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB4 LATBbits.LATB9 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定
#define lcd_stb LATFbits.LATF0 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定
#define lcd_rs LATFbits.LATF1 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定
void lcd_out(char code, char flag);
void lcd_data(char asci);
void lcd_cmd(char cmd);
void lcd_clear(void);
void lcd_init(void);
void lcd_str(char *str);
//**************************************************************************
//インクルードファイル 1lcd_lib_C30.c
//このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、
//C30コンパイラ対応等で変更したものです。
//**************************************************************************
///////////////////////////////////////////////
// 液晶表示器制御ライブラリ for C30コンパイラー
// 内蔵関数は以下
// lcd_init() ----- 初期化
// lcd_cmd(cmd) ----- コマンド出力
// lcd_data(chr) ----- 1文字表示出力
// lcd_clear() ----- 全消去
// lcd_str(str*) ----- 文字列表示
//////////////////////////////////////////////
#include "1lcd_lib_C30.h"
unsigned int _1usec; // 1μsec待つに必要なウェイト回数
unsigned int _50usec; //50μsec待つに必要なウェイト回数
unsigned long N_msec; // 1msec待つに必要なウェイト回数
//////// データ出力サブ関数
void lcd_out(char code, char flag)
{
if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット
else lcd_port_DB7 = 0;
if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット
else lcd_port_DB6 = 0;
if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット
else lcd_port_DB5 = 0;
if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット
else lcd_port_DB4 = 0;
if (flag == 0)
lcd_rs = 1; // 表示データの場合
else
lcd_rs = 0; // コマンドデータの場合
__delay32(_1usec); //1μsecウェイト
lcd_stb = 1; // strobe(E) ON (Enable)
__delay32(_1usec); // 1μsec : strobe信号の幅
lcd_stb = 0; // reset strobe
}
//////// 1文字表示関数
void lcd_data(char asci)
{
lcd_out(asci, 0); // 上位4ビット出力
lcd_out(asci<<4, 0); // 下位4ビット出力
__delay32(_50usec); //50μsecウェイト
}
/////// コマンド出力関数
void lcd_cmd(char cmd)
{
lcd_out(cmd, 1); // 上位4ビット出力
lcd_out(cmd<<4, 1); // 下位4ビット出力
if((cmd & 0x03) != 0) // clear Homeの場合
__delay32(2*N_msec); // 2msec待ち
else
__delay32(_50usec); //50μsecウェイト
}
/////// 全消去関数
void lcd_clear(void)
{
lcd_cmd(0x01); // 初期化コマンド出力
// __delay32(15*N_msec); //15msecウェイト
}
/////// 文字列出力関数
void lcd_str(char* str)
{
while(*str) //文字列終端の '\0'を検出するまで
{
lcd_data(*str); // 1文字表示
str++; //ポインタをインクリメント
}
}
/////// 初期化関数
void lcd_init(void)
{
_1usec =(unsigned int)( Clock / 4000000); // 1μsecに要するウェイト回数
//__delay32(N) : Nが11以下の場合でも11回ウェイト
_50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数
N_msec = (unsigned long int)(Clock / 4000); // 1msecに要するウェイト回数
// = Clock / 4000000*1000
__delay32(20*N_msec); //20msecウェイト
lcd_out(0x30, 1); // 8bit mode set
__delay32(5*N_msec); //5msecウェイト
lcd_out(0x30, 1); // 8bit mode set
__delay32(N_msec); //1msecウェイト
lcd_out(0x30, 1); // 8bit mode set
__delay32(N_msec); //1msecウェイト
lcd_out(0x20, 1); // 4bit mode set
__delay32(N_msec); //1msecウェイト
lcd_cmd(0x2E); // DL=0 4bit mode
lcd_cmd(0x08); // display off C=D=B=0
lcd_cmd(0x0D); // display on C=D=1 B=0
lcd_cmd(0x06); // entry I/D=1 S=0
lcd_cmd(0x02); // cursor home
}
<動作結果>
| 逓倍 | 液晶画面 上段: カウント表示 下段: 倍率 |
| 逓倍率 = 1 | ![]() |
| 逓倍率 = 10 | ![]() |
| 逓倍率 = 100 | ![]() |
| 逓倍率 = 1000 | ![]() |
| 逓倍率 = 10000 | ![]() |
■ パルスジェネレータ(0.5Hz〜200KHz)
<試作品仕様>
・周波数: 1.0Hz〜200KHz Duty:50%の矩形波パルスを発生すること。
・周波数の設定は手動インクリメント型エンコーダで行えること。
・周波数設定は ×1、×10、×100、×1000、×10000の 逓倍がHEXスイッチでおこなえること。
・周波数設定は0.5Hz単位でおこなえること。
<試作品回路図>(→回路図のPDFファイル)
・ dsPIC4013をつかった場合の回路図を以下に示します。
・ エンコーダは 秋月電子で販売されている インクリメント型エンコーダ アルファ EC16B (RE16F-40E3-L(A)-24P相当)です。

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

<プログラム例>
//*******************************************************************
// パルスジェネレータ(0.5Hz 〜 200KHz)
// dsPIC 16bit タイマ dsPIC4013
//★ ハード(JK フリップフロップ 74HC107)で1/2に分周しているので PIC単独での出力周波数は(1Hz〜400KHz)
//*******************************************************************
#include <p30f4013.h>
#include <timer.h>
#include <ports.h>
#include "1lcd_lib_C30.h"
#define b0 PORTBbits.RB5
#define b1 PORTBbits.RB4
#define b2 PORTBbits.RB3
#define b3 PORTBbits.RB2
_FOSC(CSW_FSCM_OFF & // クロック切り替えなし、フェールセイフクロックモニタなし
HS2_PLL16 //外部発振子周波数 × postscaler × PLL:16倍 → 10MHz × 1/2 × 16 = 80MHz
);
_FWDT(WDT_OFF); //ウォッチドックタイマ:OFF
_FBORPOR(PBOR_ON & //ブラウンアウトリセット機能:ON
BORV42 & //ブラウンアウト電圧:4.2V
// BORV_42 & //ブラウンアウト電圧:4.2V (旧 config 記載形式)
PWRT_64 & //パワーオンリセットタイマ64msec
MCLR_EN //MCLR機能:ON
);
_FGS(CODE_PROT_OFF); //コードプロテクト:OFF
unsigned char dummy = ' ';
signed long Freq = 2; //FF入力周波数(エンコダカウント数 24パルス/回転) 32bit
unsigned int Mag = 1; //エンコーダカウント数の周波数換算倍率
unsigned int Duty_Count16 = 1000; //タイマ2の周期設定値(=FF入力周期[μsec]×20) 16bit
unsigned long Duty_Count32 = 1000; //タイマ2の周期設定値(=FF入力周期[μsec]×20) 32bit
unsigned char AswCount = 0; //A相0検出回数
unsigned char nAswCount = 0; //A相1検出回数
unsigned char Asw;
unsigned char Rising;
unsigned long Nduty; //T23のduty設定整数
int Quot = 0,Quot0 = 0;
unsigned int Remain = 10000,Remain0 = 10000;
int N ;
char Buf[17]; //文字列のバッファー用レジスタ
void delay_ms(unsigned int N) //1msec遅延関数
{
__delay32(Clock/4000*N); //1msecのウェイト数: 80,000,000/4000 = 20,000
}
void Mag_Func() //エンコーダカウント数−周波数倍率検出 //HEXスイッチ読み込み
{
if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Mag = 1; //0
else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0))Mag = 10; //1
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1))Mag = 100; //2
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0))Mag = 1000; //3
else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1))Mag = 10000; //4
else Mag = 10000; //3
}
void _ISR _T1Interrupt(void) //液晶表示
{
IFS0bits.T1IF = 0; //IFS0レジスタの T1IF(タイマ2の割込み検出)フラグリセット
lcd_clear(); // 全消去
sprintf(Buf,"Freq=%lu.%lu[Hz]",Freq/2,(Freq % 2)* 5); //arguementがないと遅い C30のバグ?
lcd_str(Buf);
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf,"*%u.%u(multiply)",Mag/2,(Mag%2)*5); //文字列としてバッファーに収納
lcd_str(Buf);
}
void Encode() //エンコーダ読み込み
{
Mag_Func(); //エンコーダ倍率
if(PORTAbits.RA11 == 0) AswCount++; //A相検出値が0なら AswCountをインクリメント
else AswCount = 0;
if(AswCount >= 8)
{
Asw = 0; //AswCount = 8 の時 A相は0である。
AswCount = 8;
}
if(PORTAbits.RA11 == 1)nAswCount++; //A相検出値が1なら nAswCountをインクリメント
else nAswCount = 0;
if(nAswCount >= 8)
{
if(Asw == 0)Rising = 1; //A相のパルスの立上り検出
Asw = 1; //nAswCount = 8 の時 A相は0である。
nAswCount = 8;
}
if(Rising == 1) //A相パルスが立上った場合
{
Rising = 0;
if(PORTDbits.RD9 == 0)
{
Freq = Freq + Mag; //C.W.の場合
if(Freq >= 400000)Freq = 400000; //最大400KHz
}
else
{
Freq = Freq - Mag; //C.C.W.の場合
if(Freq <= 2) Freq = 2;
}
Duty_Count32 = 20000000/Freq; //Duty_Count = 50カウント × 400,000Hz/Fre
//2.5μsec(=1/400,000Hz) = 0.05μsec(=1/80,000,000Hz)×50カウント
if(Duty_Count32 <= 65535)
{
Duty_Count16 = (unsigned int)Duty_Count32;
}
else
{ //Duty0 = 0.05μsec × 65535 = 32767.5μsec = 32.7675mse
//32767.5×50 = 1638375
Quot = Duty_Count32/65535 ; //Quotient 商
Remain = Duty_Count32 % 65535; //Remainder 余り
}
}
__delay32(5000); //0.25msec(読み込み)
}
void _ISR _T2Interrupt(void) //パルス出力
{
if(Duty_Count32 <= 65535) //16ビット・高周波の場合
{
LATDbits.LATD0 = 0; //Q
LATDbits.LATD1 = 0; //nQ
PR2 = Duty_Count16; //割り込み発生までの時間設定
//50カウント → 2.5μsec(=400KHz)
LATDbits.LATD0 = 1; //
LATDbits.LATD1 = 1; //
}
else //16ビット以上の低周波の場合
{
if(Quot0 == 0) //パルスを出す場合
{
LATDbits.LATD0 = 0; //Q
LATDbits.LATD1 = 0; //nQ
PR2 = Remain0; //余りを割り込み待ち時間に設定
Quot0 = Quot; //現時点の商を記憶
Remain0 = Remain; //現時点の余りを記憶
LATDbits.LATD0 = 1; //
LATDbits.LATD1 = 1; //
}
else
{
Quot0 = Quot0 - 1; // パルスを出さないで割り込み終了
PR2 = 65535;
}
}
IFS0bits.T2IF = 0; //IFS0レジスタの T2IF(タイマ2の割込み検出)フラグリセット
}
int main(void)
{
TRISA = 0xFFFF;
ADPCFG = 0xFFFF; //デジタルポートに設定
TRISB = 0x003C; //
TRISD = 0x0200; //RD9: in
TRISF = 0;
LATFbits.LATF4 = 1; //JK FF Q1 Clear Port → 1
LATFbits.LATF5 = 1; //JK FF Q2 Clear Port → 1
//T1タイマ 液晶表示
OpenTimer1(
T1_ON & //タイマ1:ON
T1_GATE_OFF & //ゲート制御(信号がある時だけタイマが動作)OFF
T1_PS_1_256 & //プリスケーラ
T1_SYNC_EXT_OFF & //外部同期タイマはタイマ1のみ
T1_SOURCE_INT,
23438 //300msec / 0.05μsec / 256 = 23437.5
);
//T2タイマ パルス出力
OpenTimer2(
T2_ON & //連結タイマ2・タイマ3:ON
T2_GATE_OFF & //ゲート制御OFF
T2_PS_1_1 & //プリスケーラ 1/1
T2_SOURCE_INT, //クロック源: 内部クロック
// 80MHz Fosc * 1/4 = 20MHz → 0.05μsec
100 // 2.5μsec(= 0.05μsec × 50) → 400KHz
// 実測:2.5μsec
);
lcd_init(); // LCD初期化
lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF
lcd_clear(); // 全消去
sprintf(Buf,"Pulse Generator2 %c",dummy);//arguementがないと遅い C30のバグ?
lcd_str(Buf);
//液晶表示
lcd_cmd(0xC0); //2目表示行目の先頭へ
sprintf(Buf,"Start !! %c",dummy); //文字列としてバッファーに収納
lcd_str(Buf); // 開始メッセージ2行
delay_ms(1000);
ConfigIntTimer1(T1_INT_PRIOR_2 & T1_INT_ON ); //割込みレベル2 連結タイマ1割込みON
ConfigIntTimer2(T2_INT_PRIOR_5 & T2_INT_ON ); //割込みレベル5 連結タイマ2割込みON
EnableIntT1;
EnableIntT2;
//割込み許可
while(1)
{
Encode();
}
return 0;
}
//*************************************************************************
//インクルードファイル 1lcd_lib_C30.h
//このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、
//C30コンパイラ対応等でに変更したものです。
//*************************************************************************
#include "p30f4013.h"
#define Clock 80000000 // 単位はHzで指定
// LCDポート設定
#define lcd_port_DB7 LATBbits.LATB12 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB6 LATBbits.LATB11 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB5 LATBbits.LATB10 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定
#define lcd_port_DB4 LATBbits.LATB9 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定
#define lcd_stb LATFbits.LATF0 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定
#define lcd_rs LATFbits.LATF1 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定
void lcd_out(char code, char flag);
void lcd_data(char asci);
void lcd_cmd(char cmd);
void lcd_clear(void);
void lcd_init(void);
void lcd_str(char *str);
//**************************************************************************
//インクルードファイル 1lcd_lib_C30.c
//このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、
//C30コンパイラ対応等で変更したものです。
//**************************************************************************
///////////////////////////////////////////////
// 液晶表示器制御ライブラリ for C30コンパイラー
// 内蔵関数は以下
// lcd_init() ----- 初期化
// lcd_cmd(cmd) ----- コマンド出力
// lcd_data(chr) ----- 1文字表示出力
// lcd_clear() ----- 全消去
// lcd_str(str*) ----- 文字列表示
//////////////////////////////////////////////
#include "1lcd_lib_C30.h"
unsigned int _1usec; // 1μsec待つに必要なウェイト回数
unsigned int _50usec; //50μsec待つに必要なウェイト回数
unsigned long N_msec; // 1msec待つに必要なウェイト回数
//////// データ出力サブ関数
void lcd_out(char code, char flag)
{
if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット
else lcd_port_DB7 = 0;
if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット
else lcd_port_DB6 = 0;
if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット
else lcd_port_DB5 = 0;
if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット
else lcd_port_DB4 = 0;
if (flag == 0)
lcd_rs = 1; // 表示データの場合
else
lcd_rs = 0; // コマンドデータの場合
__delay32(_1usec); //1μsecウェイト
lcd_stb = 1; // strobe(E) ON (Enable)
__delay32(_1usec); // 1μsec : strobe信号の幅
lcd_stb = 0; // reset strobe
}
//////// 1文字表示関数
void lcd_data(char asci)
{
lcd_out(asci, 0); // 上位4ビット出力
lcd_out(asci<<4, 0); // 下位4ビット出力
__delay32(_50usec); //50μsecウェイト
}
/////// コマンド出力関数
void lcd_cmd(char cmd)
{
lcd_out(cmd, 1); // 上位4ビット出力
lcd_out(cmd<<4, 1); // 下位4ビット出力
if((cmd & 0x03) != 0) // clear Homeの場合
__delay32(2*N_msec); // 2msec待ち
else
__delay32(_50usec); //50μsecウェイト
}
/////// 全消去関数
void lcd_clear(void)
{
lcd_cmd(0x01); // 初期化コマンド出力
// __delay32(15*N_msec); //15msecウェイト
}
/////// 文字列出力関数
void lcd_str(char* str)
{
while(*str) //文字列終端の '\0'を検出するまで
{
lcd_data(*str); // 1文字表示
str++; //ポインタをインクリメント
}
}
/////// 初期化関数
void lcd_init(void)
{
_1usec =(unsigned int)( Clock / 4000000); // 1μsecに要するウェイト回数
//__delay32(N) : Nが11以下の場合でも11回ウェイト
_50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数
N_msec = (unsigned long int)(Clock / 4000); // 1msecに要するウェイト回数
// = Clock / 4000000*1000
__delay32(20*N_msec); //20msecウェイト
lcd_out(0x30, 1); // 8bit mode set
__delay32(5*N_msec); //5msecウェイト
lcd_out(0x30, 1); // 8bit mode set
__delay32(N_msec); //1msecウェイト
lcd_out(0x30, 1); // 8bit mode set
__delay32(N_msec); //1msecウェイト
lcd_out(0x20, 1); // 4bit mode set
__delay32(N_msec); //1msecウェイト
lcd_cmd(0x2E); // DL=0 4bit mode
lcd_cmd(0x08); // display off C=D=B=0
lcd_cmd(0x0D); // display on C=D=1 B=0
lcd_cmd(0x06); // entry I/D=1 S=0
lcd_cmd(0x02); // cursor home
}
<動作結果>
| 出力周波数 | 液晶表示 | パルス波形(フリップフロップ出力) | フリップフロップ入力波形 (PIC出力波形) |
| 1.0Hz | ![]() |
![]() |
ー |
| 10Hz | ![]() |
![]() |
ー |
| 100Hz | ![]() |
![]() |
ー |
| 1KHzHz | ![]() |
![]() |
ー |
| 10KHz |
![]() |
![]() |
ー |
| 100KHz | ![]() |
![]() |
ー |
| 200KHz | ![]() |
![]() |
![]() |
■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 16進数表示
<HI-TECH編>
液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
・制御対象は7セグメント液晶1個とする。
・16進スイッチの値を 液晶に16進数で表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれまし

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

<プログラム例>
//HI-TEC セグメント液晶スタティック制御 PIC16F1937
// Hex SW 16進表示
#include <htc.h>
#define _XTAL_FREQ 500000 //セラミック発振子:20MHz (この設定で ディレイ関数__delay_ms()が設計の遅れ時間となる 原因不明 バグ?)
//#define _XTAL_FREQ 20000000 //セラミック発振子:20MHz ディレイ関数用
// コンフィギュレーションの設定
__CONFIG(
FOSC_HS & // EXTRC Oscillator, RC on RA7/OSC1/CLKIN
WDTE_OFF & // Power-up Timer Enable bit// PWRT disabled
PWRTE_ON & // MCLR Pin Function Select// RE3/MCLR/VPP pin function is MCLR
MCLRE_ON & // RE3/MCLR/VPP pin function is digital input
CP_OFF & // Program memory code protection is enabled
CPD_OFF & // Data memory code protection is enabled
BOREN_OFF & // Clock Out Enable bit// CLKOUT function is disabled. I/O or oscillator function on RA6/CLKOUT
CLKOUTEN_OFF & // CLKOUT function is enabled on RA6/CLKOUT pin
IESO_OFF & // Fail Clock Monitor Enable// Fail-Safe Clock Monitor is enabled
FCMEN_ON // Fail-Safe Clock Monitor is disabled
);
__CONFIG(
WRT_OFF & // 000h to 1FFh write protected, 200h to 1FFFh may be modified by EECON control
PLLEN_OFF & // 4x PLL disabled (PLLをONにしても動作時間に影響ない 原因不明 バグ?)
STVREN_OFF &// Brown-out Reset Voltage selection// Brown-out Reset Voltage (VBOR) set to 1.9 V
// BORV_19 & // Brown-out Reset Voltage (VBOR) set to 2.7 V
// DEBUG_OFF & // Background debugger is enabled
LVP_OFF // HV on MCLR/VPP must not be used for programming
);
#define b0 PORTCbits.RC3
#define b1 PORTCbits.RC2
#define b2 PORTCbits.RC1
#define b3 PORTCbits.RC0
unsigned int Seg[16] = {0b00111111, //0
0b00000110, //1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111, // 9
0b01110111, //A
0b01111100, //b
0b00111001, //C
0b01011110, //d
0b01111001, //E
0b01110001}; //F
unsigned int Count;
void delay_ms(unsigned long int msec) //1msec delay function
{
while(msec)
{
msec--;
__delay_ms(1); //1msec delay
}
}
void main()
{
ANSELA = 0; //Aポートをデジタルポートに
ANSELB = 0; //Bポートをデジタルポートに
ANSELE = 0; //Eポートをデジタルポートに
TRISA = 0;
TRISB = 0;
TRISC = 0x0F; //b0-b3 in port
// LCDPSレジスタ(位相レジスタ)
LCDPSbits.WFT = 0; //タイプAの位相が各コモンタイプ内で変化する
LCDPSbits.BIASMD = 0; //スタティックバイアスモードの場合は0にセット
LCDPSbits.LCDA = 0; //LCDドライバモジュールは非アクティブ
LCDPSbits.WA = 0; // LCDへの書き込みは許可されていない。
LCDPSbits.LP3 = 0; //LDCクロックのプリスケーラ 0000: 1/1
LCDPSbits.LP2 = 0; //1111: 1/16 1000: 1/9 etc
LCDPSbits.LP1 = 0;
LCDPSbits.LP0 = 0;
// LCDPS = 0x08; // タイプAでスタティック、1:9
LCDSE1 = 0xFF; // セグメント1の全セグメント有効化
// LCDSE0 = 0xFF; // 全セグメント有効化
// LCDSE1 = 0xFF; // 全セグメント有効化
// LCDSE2 = 0xFF; // 全セグメント有効化
//LCDCONレジスタ(LCDドライバ有効・無効、LCDクロックソース選択)
LCDCONbits.LCDEN = 1; //LCDドライバー: 有効
LCDCONbits.SLPEN = 0; //スリープ時のLCDドライバー: 無効
LCDCONbits.WERR = 0; // LCDの書き込みエラーなし
LCDCONbits.CS0 = 0; //LCDクロックソース選択ビット
LCDCONbits.CS1 = 0; //同上
//00:Fosc/256
//01:T1OSC(Timer1) 1x:LFINTOSC(31KHz)
//LCDCON = 0x84;//0b10000100 // スタティック、副発振有効itits
LCDCONbits.LMUX1 = 0; //00: スタティック制御 //スタティック・マルチプレックス制御選択
LCDCONbits.LMUX0 = 0; //01: 1/2マルチプレックス、 02: 1/3マルチプレックス、 03: 1/4マルチプレックス
//LCDDATA1-3レジスタ(データレジスタ)
LCDDATA1 = 0xFF; // セグメント1の全セグメントオン
//LCDDATA0 = 0xFF; // 全セグメントオン
//LCDDATA1 = 0xFF; // 全セグメントオン
//LCDDATA2 = 0xFF; // 全セグメントオン
//LCDRLレジスタ(リファレンス ラダー) クロック極性切り替わり時の抵抗値設定、AモードとBモードとの割合設定による省電力に係るレジスタ
LCDRLbits.LRLAP1 = 0; //LCDリファレンスラダーAタイムの電力制御ビット
LCDRLbits.LRLAP0 = 1; //同上
//01: 低電力モード // 10: 中電力モード 11: 高電力モード
LCDRLbits.LRLBP1 = 0; //LCDリファレンスラダーBタイムの電力制御ビット
LCDRLbits.LRLBP0 = 1; //同上
//01: 低電力モード //10: 中電力モード 11: 高電力モード
LCDRLbits.LRLAT2 = 1; //LCDリファレンスラダーAタイムインターバル制御ビットs
LCDRLbits.LRLAT1 = 1; //同上
LCDRLbits.LRLAT0 = 1; //同上
//111: (WFT=0が選択してあるので)タイプAの波形は、内部LCDリファレンスが、7クロック間電力モードAで9クロック間電力モードBとなる。
//111: (WFT=1を選択している場合は)タイプBの波形は、内部LCDリファレンスが、7クロック間電力モードAで25クロック間電力モードBとなる。
// LCDRL = 0x57; // 低電流モード
//LCDREFレジスタ(リファレンス電圧設定、LCDバイアス電圧設定)
LCDREFbits.LCDIRE = 1; //1: 内部リファレンス有効 //0: 無効
LCDREFbits.LCDIRS = 0; //0: LCDの内部のコントラスト制御はVddを使用する。 //内部のリファレンス電圧のソース電源選択ビット
//1: LCDの内部のコントラスト制御はFVRの3.072Vを使用する。
LCDREFbits.LCDIRI = 0; //内部リファレンスラダーアイドルイネーブルビット
//0: LCDのFVRバッファーは、LCDリファレンスのパワーモードを無視する。
LCDREFbits.VLCD3PE = 0; //VCLD3ピンは接続されない //外部LCDバイアス電圧を使用する場合に接続する
LCDREFbits.VLCD2PE = 0; //VCLD2ピンは接続されない
LCDREFbits.VLCD1PE = 0; //VCLD1ピンは接続されない
// LCDREF = 0x80; //0b10000000 // 内蔵バイアス、VLCD入力なし
//LCDCSTレジスタ(コントラスト設定)
LCDCSTbits.LCDCST2 = 0; //LCDのコントラスト制御ビット
LCDCSTbits.LCDCST1 = 1; //同上
LCDCSTbits.LCDCST0 = 1; //同上
//011 ラダー抵抗は最大抵抗の3/7、コントラストは中程度
//000 ラダー抵抗は最小(ラダー抵抗は短絡)、最大コントラスト
//111 ラダー抵抗は最大、最小コントラスト
//LCDCST = 0x03; //0b00000011 // 中コントラスト
//T1CON レジスタ(Timer1 Control Resister)
TMR1CS1 = 0; //Timer1 clock source: Fosc/4 //Timer1 Clock Source Select bits
TMR1CS0 = 0; //TMR1CS<1:0> = 00 → Fosc/4 // 01 → Fosc
T1CKPS1 = 0; //プリスケーラ 1/1 //Prescale Select bits
T1CKPS0 = 0; //T1CKPS<1:0> = 00 → 1/1 //10→1/4 01→1/2 00→1/1
T1OSCEN = 0; //LP Oscillator Enble Control bit
nT1SYNC = 0; //Timer1 External Clock Input Synchronization Control bit
TMR1ON = 1; //Enable Timer1 //Timer1 On bit
//T1GCON レジスタ(Timer1 Gate Control Resister) // ゲート機能なし
TMR1GE = 0; //Timer1 Gate Enable bit
T1GPOL = 0; //Timer1 Gate Polarity bit
T1GTM = 0; //Timer1 Gate Toggle Mode bit
T1GSPM = 0; //Timer1 Gate Single Pulse Mode bit
T1GGO = 0; //Timer1 Gate Single-Pulse Acquisition Status bit
T1GVAL = 0; //Timer1 Gate current State bit
T1GSS1 = 0; //Timer1 Gate Source Select bits
T1GSS0 = 0;
TMR1H = 0xFB; //
TMR1L = 0x1E; //
__delay_ms(1);
while(1)
{
if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[0];
else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[1];
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[2];
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0)) LCDDATA1 = Seg[3];
else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[4];
else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[5];
else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[6];
else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 0)) LCDDATA1 = Seg[7];
else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[8];
else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[9];
else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[10];
else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 0)) LCDDATA1 = Seg[11];
else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 1)) LCDDATA1 = Seg[12];
else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 0)) LCDDATA1 = Seg[13];
else if((b3 == 0) && (b2 == 0) && (b1 == 0) && (b0 == 1)) LCDDATA1 = Seg[14];
else LCDDATA1 = Seg[15];
}
}
<動作結果>
HEX スイッチをFに回した時の写真です。
| 液晶表示 | 電圧波形 |
|
| 表示セグメント セグメント印加電圧 上段: 4A(2v/div) 下段: COM(2v/div) |
非表示セグメント 上段: 4B(2v/div) 下段: COM(2v/div) |
|
![]() |
![]() |
![]() |
| 25msec/div デジタルオシロスコープ ATTEN製(中国) ADS1102CA |
||
■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 カウンタ
<HI-TECH編>
液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
・制御対象は7セグメント液晶1個とする。
・周期1秒の16進カウンタを製作のこと。 また、 Fの次は 0に戻ること
すなわち 0 → 1 → 2 → 3 ……… C → d → E → F → 0 → 1
<試作品回路図>(→回路図のPDFファイル)
PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

<プログラム例>
//HI-TEC セグメント液晶スタティック制御 PIC16F1937
// 1桁 16進カウンタ
#include <htc.h>
#define _XTAL_FREQ 500000 //セラミック発振子:20MHz (この設定で ディレイ関数__delay_ms()が設計の遅れ時間となる 原因不明 バグ?)
//#define _XTAL_FREQ 20000000 //セラミック発振子:20MHz ディレイ関数用
// コンフィギュレーションの設定
__CONFIG(
FOSC_HS & // EXTRC Oscillator, RC on RA7/OSC1/CLKIN
WDTE_OFF & // Power-up Timer Enable bit// PWRT disabled
PWRTE_ON & // MCLR Pin Function Select// RE3/MCLR/VPP pin function is MCLR
MCLRE_ON & // RE3/MCLR/VPP pin function is digital input
CP_OFF & // Program memory code protection is enabled
CPD_OFF & // Data memory code protection is enabled
BOREN_OFF & // Clock Out Enable bit// CLKOUT function is disabled. I/O or oscillator function on RA6/CLKOUT
CLKOUTEN_OFF & // CLKOUT function is enabled on RA6/CLKOUT pin
IESO_OFF & // Fail Clock Monitor Enable// Fail-Safe Clock Monitor is enabled
FCMEN_ON // Fail-Safe Clock Monitor is disabled
);
__CONFIG(
WRT_OFF & // 000h to 1FFh write protected, 200h to 1FFFh may be modified by EECON control
PLLEN_OFF & // 4x PLL disabled (PLLをONにしても動作時間に影響ない 原因不明 バグ?)
STVREN_OFF &// Brown-out Reset Voltage selection// Brown-out Reset Voltage (VBOR) set to 1.9 V
// BORV_19 & // Brown-out Reset Voltage (VBOR) set to 2.7 V
// DEBUG_OFF & // Background debugger is enabled
LVP_OFF // HV on MCLR/VPP must not be used for programming
);
unsigned int Seg[16] = {0b00111111, //0
0b00000110, //1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111, // 9
0b01110111, //A
0b01111100, //b
0b00111001, //C
0b01011110, //d
0b01111001, //E
0b01110001}; //F
unsigned int Count;
int ix ;
void delay_ms(unsigned long int msec) //1msec delay function
{
while(msec)
{
msec--;
__delay_ms(1); //1msec delay
}
}
void interrupt isr(void) //10msec毎の割り込み
{
TMR1IF = 0; //フラグクリア
//アップカウンタの値設定
//Clock: 20MHz/4 → 5MHz 0.2μsec
// 10msec毎の割り込みを行う
//プリスケーラ 1/1 //Prescale Select bits
// <計算>
// (65536 -N)*0.2*1 = 10000 [μsec]
// N = 65536 - 50000 = 15536
// 15536 = 0x3C6B 実測割り込みインターバル = 400msec(原因不明 バグ?)
// 対応: 10000μsec * 1/40 = 250μsec
// (56636 -N)*0.2*1 = 250 [μsec]
// N = 65536 - 1250 = 642486 = 0xFB1E (実測割り込みインターバル: 10msec)
TMR1H = 0xFB; //
TMR1L = 0x1E; //
Count++;
if(Count >= 100)
{
Count = 0;
LCDDATA1 = Seg[ix]; //液晶セグメント表示
ix++;
if(ix >=16)ix = 0;
}
}
void main()
{
ANSELA = 0; //Aポートをデジタルポートに
ANSELB = 0; //Bポートをデジタルポートに
ANSELE = 0; //Eポートをデジタルポートに
TRISA = 0;
TRISB = 0;
TRISC = 0;
// LCDPSレジスタ(位相レジスタ)
LCDPSbits.WFT = 0; //タイプAの位相が各コモンタイプ内で変化する
LCDPSbits.BIASMD = 0; //スタティックバイアスモードの場合は0にセット
LCDPSbits.LCDA = 0; //LCDドライバモジュールは非アクティブ
LCDPSbits.WA = 0; // LCDへの書き込みは許可されていない。
LCDPSbits.LP3 = 0; //LDCクロックのプリスケーラ 0000: 1/1
LCDPSbits.LP2 = 0; //1111: 1/16 1000: 1/9 etc
LCDPSbits.LP1 = 0;
LCDPSbits.LP0 = 0;
// LCDPS = 0x08; // タイプAでスタティック、1:9
LCDSE1 = 0xFF; // セグメント1の全セグメント有効化
// LCDSE0 = 0xFF; // 全セグメント有効化
// LCDSE1 = 0xFF; // 全セグメント有効化
// LCDSE2 = 0xFF; // 全セグメント有効化
//LCDCONレジスタ(LCDドライバ有効・無効、LCDクロックソース選択)
LCDCONbits.LCDEN = 1; //LCDドライバー: 有効
LCDCONbits.SLPEN = 0; //スリープ時のLCDドライバー: 無効
LCDCONbits.WERR = 0; // LCDの書き込みエラーなし
LCDCONbits.CS0 = 0; //LCDクロックソース選択ビット
LCDCONbits.CS1 = 0; //同上
//00:Fosc/256
//01:T1OSC(Timer1) 1x:LFINTOSC(31KHz)
//LCDCON = 0x84;//0b10000100 // スタティック、副発振有効itits
LCDCONbits.LMUX1 = 0; //00: スタティック制御 //スタティック・マルチプレックス制御選択
LCDCONbits.LMUX0 = 0; //01: 1/2マルチプレックス、 02: 1/3マルチプレックス、 03: 1/4マルチプレックス
//LCDDATA1-3レジスタ(データレジスタ)
LCDDATA1 = 0xFF; // セグメント1の全セグメントオン
//LCDDATA0 = 0xFF; // 全セグメントオン
//LCDDATA1 = 0xFF; // 全セグメントオン
//LCDDATA2 = 0xFF; // 全セグメントオン
//LCDRLレジスタ(リファレンス ラダー) クロック極性切り替わり時の抵抗値設定、AモードとBモードとの割合設定による省電力に係るレジスタ
LCDRLbits.LRLAP1 = 0; //LCDリファレンスラダーAタイムの電力制御ビット
LCDRLbits.LRLAP0 = 1; //同上
//01: 低電力モード // 10: 中電力モード 11: 高電力モード
LCDRLbits.LRLBP1 = 0; //LCDリファレンスラダーBタイムの電力制御ビット
LCDRLbits.LRLBP0 = 1; //同上
//01: 低電力モード //10: 中電力モード 11: 高電力モード
LCDRLbits.LRLAT2 = 1; //LCDリファレンスラダーAタイムインターバル制御ビットs
LCDRLbits.LRLAT1 = 1; //同上
LCDRLbits.LRLAT0 = 1; //同上
//111: (WFT=0が選択してあるので)タイプAの波形は、内部LCDリファレンスが、7クロック間電力モードAで9クロック間電力モードBとなる。
//111: (WFT=1を選択している場合は)タイプBの波形は、内部LCDリファレンスが、7クロック間電力モードAで25クロック間電力モードBとなる。
// LCDRL = 0x57; // 低電流モード
//LCDREFレジスタ(リファレンス電圧設定、LCDバイアス電圧設定)
LCDREFbits.LCDIRE = 1; //1: 内部リファレンス有効 //0: 無効
LCDREFbits.LCDIRS = 0; //0: LCDの内部のコントラスト制御はVddを使用する。 //内部のリファレンス電圧のソース電源選択ビット
//1: LCDの内部のコントラスト制御はFVRの3.072Vを使用する。
LCDREFbits.LCDIRI = 0; //内部リファレンスラダーアイドルイネーブルビット
//0: LCDのFVRバッファーは、LCDリファレンスのパワーモードを無視する。
LCDREFbits.VLCD3PE = 0; //VCLD3ピンは接続されない //外部LCDバイアス電圧を使用する場合に接続する
LCDREFbits.VLCD2PE = 0; //VCLD2ピンは接続されない
LCDREFbits.VLCD1PE = 0; //VCLD1ピンは接続されない
// LCDREF = 0x80; //0b10000000 // 内蔵バイアス、VLCD入力なし
//LCDCSTレジスタ(コントラスト設定)
LCDCSTbits.LCDCST2 = 0; //LCDのコントラスト制御ビット
LCDCSTbits.LCDCST1 = 1; //同上
LCDCSTbits.LCDCST0 = 1; //同上
//011 ラダー抵抗は最大抵抗の3/7、コントラストは中程度
//000 ラダー抵抗は最小(ラダー抵抗は短絡)、最大コントラスト
//111 ラダー抵抗は最大、最小コントラスト
//LCDCST = 0x03; //0b00000011 // 中コントラスト
//T1CON レジスタ(Timer1 Control Resister)
TMR1CS1 = 0; //Timer1 clock source: Fosc/4 //Timer1 Clock Source Select bits
TMR1CS0 = 0; //TMR1CS<1:0> = 00 → Fosc/4 // 01 → Fosc
T1CKPS1 = 0; //プリスケーラ 1/1 //Prescale Select bits
T1CKPS0 = 0; //T1CKPS<1:0> = 00 → 1/1 //10→1/4 01→1/2 00→1/1
T1OSCEN = 0; //LP Oscillator Enble Control bit
nT1SYNC = 0; //Timer1 External Clock Input Synchronization Control bit
TMR1ON = 1; //Enable Timer1 //Timer1 On bit
//T1GCON レジスタ(Timer1 Gate Control Resister) // ゲート機能なし
TMR1GE = 0; //Timer1 Gate Enable bit
T1GPOL = 0; //Timer1 Gate Polarity bit
T1GTM = 0; //Timer1 Gate Toggle Mode bit
T1GSPM = 0; //Timer1 Gate Single Pulse Mode bit
T1GGO = 0; //Timer1 Gate Single-Pulse Acquisition Status bit
T1GVAL = 0; //Timer1 Gate current State bit
T1GSS1 = 0; //Timer1 Gate Source Select bits
T1GSS0 = 0;
TMR1H = 0xFB; //
TMR1L = 0x1E; //
TMR1IE = 1; // タイマ1割り込み許可
PEIE = 1; // 周辺割り込み許可許可
GIE = 1; // グローバル割り込み許可
__delay_ms(1);
while(1)
{
/*
for(ix = 0; ix<16; ix++)
{
LCDDATA1 = Seg[ix];
delay_ms(1000);
}
*/
}
}
<動作結果>
6がカウントされ 液晶に表示された場合の写真です。

■ 外付けXORによる 液晶セグメント スタティック駆動式 16進数表示
液晶の各セグメントに印加される平均電圧は0vにする必要があります。
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動により各液晶セグメントを直接制御する
・PICの出力I/Oは スタティック液晶駆動用ではない一般のI/Oを用い、 外付け回路により液晶印可電圧平均値を0Vにすること。
・液晶の駆動周波数は302Hzとする。
・制御対象は7セグメント液晶1個とする。
・16進スイッチの値を 液晶に16進数で表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

<プログラム例>
// XORを使用した 液晶セグメントスタティック駆動制御
// HeXスイッチの値表示
// PIC18F452, C18コンパイラ
#include <p18f452.h>
#include <delays.h>
#pragma config OSC = HS // f = 20MHz
#pragma config WDT = OFF
#pragma config LVP = OFF
//入力ポート 設定
#define b0 PORTDbits.RD0
#define b1 PORTCbits.RC3
#define b2 PORTCbits.RC1
#define b3 PORTCbits.RC0
//出力ポート 設定
#define A PORTCbits.RC7
#define B PORTCbits.RC6
#define C PORTCbits.RC5
#define D PORTCbits.RC4
#define E PORTAbits.RA0
#define F PORTBbits.RB7
#define G PORTBbits.RB6
void Func_0(){G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;} // 0 を表示
void Func_1(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;} // 1 を表示
void Func_2(){G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;} // 2 を表示
void Func_3(){G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;} //3 を表示
void Func_4(){G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;} //4 を表示
void Func_5(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;} //5 を表示
void Func_6(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;} //6 を表示
void Func_7(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;} //7 を表示
void Func_8(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;} //8 を表示
void Func_9(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;} //9 を表示
void Func_A(){G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;} //A を表示
void Func_b(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;} //b を表示
void Func_C(){G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;} //C を表示
void Func_d(){G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;} //d を表示
void Func_E(){G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;} //E を表示
void Func_F(){G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;} //F を表示
void delay_ms (long int cycle) // CCSコンパイラと同じ delay_ms(long int) 関数を設計
{
long int i = 0;
for (i = 0; i < cycle*5; i++)Delay1KTCYx(1); // 0.05μsec × 4 × 1000 = 0.2msec
}
void main (void)
{
TRISA = 0;
TRISB = 0;
TRISC = 0b00001011;
TRISD = 0b00000001;
// CCP: PWMモード 1.2KHz duty=1/2
T2CONbits.T2CKPS1 = 1; // prescale: 1/16
CCP1CON = 0b00111111; //bit5,4 PWM duty cycle //bit3,2 =11 → PWM mode
PR2 = 0xFF; // PWM period = (PR2 + 1)*4*Tosc*(TMR2prescale value)
TMR2 = 0x7F; // = (256 + 1) * 4 * 0.05μsec * 16
T2CONbits.TMR2ON = 1; // = 822.4μsec = 0.8224msec(1.215KHz)(実測:1.22KHz) → 液晶クロック=1.21KHz / 4 = 302Hz
CCPR1L = 0x7F; // PWM duty cycle = CCPR1L:CCPCON<5:4> * Tosc * (TMR2prescale value)
// = 0b01111111 11(511) * 0.05 * 256
//
while (1)
{
if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Func_0();
else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_1();
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_2();
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_3();
else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_4();
else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_5();
else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_6();
else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 0)) Func_7();
else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 1)) Func_8();
else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_9();
else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_A();
else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_b();
else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_C();
else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_d();
else if((b3 == 0) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_E();
else Func_F();
/*
PORTDbits.RD1 = 0; // RD1 LED ON
delay_ms(1000); //1000msec delay
PORTDbits.RD1 = 1; // BポートのLED OFF
delay_ms(1000); // 1000msec delay
*/
}
}
<動作結果>
HEXスイッチの7を選択した時の表示の写真です。
| 液晶表示 | 電圧波形 |
|
| 表示液晶セグメント 上段: 4A (2v/div) 下段: COM (2v/div) |
非表示液晶セグメント 上段: 4G(2v/div) 下段: COM(2v/div) |
|
![]() |
![]() |
![]() |
| 1msec/div デジタルオシロスコープ ATTEN製(中国) ADS1102CA |
||
■ 外付けXORによる 液晶セグメント スタティック駆動式 カウンタ
液晶の各セグメントに印加される平均電圧は0vにする必要があります。
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動により各液晶セグメントを直接制御する
・PICの出力I/Oは スタティック液晶駆動用ではない一般のI/Oを用い、 外付け回路により液晶印可電圧平均値を0Vにすること。
・液晶の駆動周波数は302Hzとする。
・制御対象は7セグメント液晶1個とする。
・周期1秒の16進カウンタを製作のこと。 また、 Fの次は 0に戻ること
すなわち 0 → 1 → 2 → 3 ……… C → d → E → F → 0 → 1
<試作品回路図>(→回路図のPDFファイル)
PIC16F1937、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

<プログラム例>
// XORを使用した 液晶セグメントスタティック駆動制御
// カウンタ
// PIC18F452, C18コンパイラ
#include <p18f452.h>
#include <delays.h>
#include <timers.h>
#pragma config OSC = HS // f = 20MHz
#pragma config WDT = OFF
#pragma config LVP = OFF
//出力ポート 設定
#define A PORTCbits.RC7
#define B PORTCbits.RC6
#define C PORTCbits.RC5
#define D PORTCbits.RC4
#define E PORTAbits.RA0
#define F PORTBbits.RB7
#define G PORTBbits.RB6
unsigned long int Count1 = 0;
unsigned long int Count2 = 0;
int LED = 0;
void Func_0(){G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;} // 0 を表示
void Func_1(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;} // 1 を表示
void Func_2(){G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;} // 2 を表示
void Func_3(){G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;} //3 を表示
void Func_4(){G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;} //4 を表示
void Func_5(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;} //5 を表示
void Func_6(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;} //6 を表示
void Func_7(){G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;} //7 を表示
void Func_8(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;} //8 を表示
void Func_9(){G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;} //9 を表示
void Func_A(){G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;} //A を表示
void Func_b(){G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;} //b を表示
void Func_C(){G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;} //C を表示
void Func_d(){G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;} //d を表示
void Func_E(){G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;} //E を表示
void Func_F(){G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;} //F を表示
void delay_ms (long int cycle) // CCSコンパイラと同じ delay_ms(long int) 関数を設計
{
long int i = 0;
for (i = 0; i < cycle*5; i++)Delay1KTCYx(1); // 0.05μsec × 4 × 1000 = 0.2msec
}
#pragma interrupt my_Func // 10msec タイマ1 インターバル割り込み
#pragma code isrcode = 0x08
void isr_direct(void)
{ _asm goto my_Func _endasm }
#pragma code
void my_Func(void)
{
PIR1bits.TMR1IF = 0; // タイマ1割り込みフラグをクリアする
WriteTimer1(59286); // 0.05μsec × 4 × 8 × 6250 = 10000μsec = 10msec (at システムクロック20MHz)
// 256×256 - 6250 = 59286
// タイマ0:16bitアップカウントタイマ → オーバーフローで割込み発生
Count1++;
if(Count1 >= 100) //1秒毎に
{
Count1 = 0;
if(Count2 == 0)Func_0();
else if(Count2 == 1) Func_1();
else if(Count2 == 2) Func_2();
else if(Count2 == 3) Func_3();
else if(Count2 == 4) Func_4();
else if(Count2 == 5) Func_5();
else if(Count2 == 6) Func_6();
else if(Count2 == 7) Func_7();
else if(Count2 == 8) Func_8();
else if(Count2 == 9) Func_9();
else if(Count2 == 10) Func_A();
else if(Count2 == 11) Func_b();
else if(Count2 == 12) Func_C();
else if(Count2 == 13) Func_d();
else if(Count2 == 14) Func_E();
else Func_F();
Count2++;
if(Count2 >= 16)Count2 = 0;
if(LED == 1)
{
PORTDbits.RD1 = 0; // RD1 LED ON
LED = 0;
}
else
{
PORTDbits.RD1 = 1; // BポートのLED OFF
LED = 1;
}
}
}
void main (void)
{
TRISA = 0;
TRISB = 0;
TRISC = 0b00001011;
TRISD = 0b00000001;
// CCP: PWMモード 1.2KHz duty=1/2
T2CONbits.T2CKPS1 = 1; // prescale: 1/16
CCP1CON = 0b00111111; //bit5,4 PWM duty cycle //bit3,2 =11 → PWM mode
PR2 = 0xFF; // PWM period = (PR2 + 1)*4*Tosc*(TMR2prescale value)
TMR2 = 0x7F; // = (256 + 1) * 4 * 0.05μsec * 16
T2CONbits.TMR2ON = 1; // = 822.4μsec = 0.8224msec(1.215KHz)(実測:1.22KHz) → 液晶クロック=1.21KHz / 4 = 302Hz
CCPR1L = 0x7F; // PWM duty cycle = CCPR1L:CCPCON<5:4> * Tosc * (TMR2prescale value)
// = 0b01111111 11(511) * 0.05 * 256
//
//タイマ0の設定
OpenTimer1
(
TIMER_INT_ON & //割込み:ON
T1_16BIT_RW & //16 bit モードに設定 vs 8bit モード( T0_8BIT )
T1_SOURCE_INT & //内部クロック使用
T1_PS_1_8 & //8ビットプリスケーラ 1/8 vs 1/1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256
T1_OSC1EN_OFF
);
WriteTimer1(59286);
RCONbits.IPEN = 0; //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0)
PIE1bits.TMR1IE = 1; //タイマ1割込み許可
INTCONbits.PEIE =1; //周辺割込み許可
//INTCONレジスタの b6ビット : 低位割込み許可/禁止(割り込み優先順位制御 有りの場合)
INTCONbits.GIE = 1; //全割込み許可
//INTCONレジスタの b7ビット : 高位割込み許可/禁止(割り込み優先順位制御 有りの場合)
while (1)
{
}
}
<動作結果>
カウント値が9の時の写真です。

■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 16進数表示
<C18編>
液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
・制御対象は7セグメント液晶1個とする。
・16進スイッチの値を 液晶に16進数で表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC18F85J90、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
PIM内部の接続は何故かトリッキーな接続となっているので設計には十分気おつけることが必要です。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれまし

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

<プログラム例>
/*
HexSwの値を LCDに表示
*/
#include <p18f85J90.h>
#include <stdio.h>
#include <delays.h>
#pragma config FOSC = HS // システムクロック=20MHz
#pragma config XINST = OFF
#pragma config WDTEN = OFF //ウォッチドックタイマ OFF
//入力ポート 設定
#define b0 PORTHbits.RH0
#define b1 PORTGbits.RG2
#define b2 PORTCbits.RC1
#define b3 PORTGbits.RG3
void Func_0(){LCDDATA0 = 0b0111111;} // 0 を表示 //G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;
void Func_1(){LCDDATA0 = 0b00000110;} // 1 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;
void Func_2(){LCDDATA0 = 0b01011011;} // 2 を表示 //G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;
void Func_3(){LCDDATA0 = 0b01001111;} //3 を表示 //G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;
void Func_4(){LCDDATA0 = 0b01100110;} //4 を表示 //G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;
void Func_5(){LCDDATA0 = 0b01101101;} //5 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;
void Func_6(){LCDDATA0 = 0b01111101;} //6 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;
void Func_7(){LCDDATA0 = 0b00000111;} //7 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;
void Func_8(){LCDDATA0 = 0b01111111;} //8 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;
void Func_9(){LCDDATA0 = 0b01101111;} //9 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;
void Func_A(){LCDDATA0 = 0b01110111;} //A を表示 //G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;
void Func_b(){LCDDATA0 = 0b01111100;} //b を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;
void Func_C(){LCDDATA0 = 0b00111001;} //C を表示 //G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;
void Func_d(){LCDDATA0 = 0b01011110;} //d を表示 //G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;
void Func_E(){LCDDATA0 = 0b01111001;} //E を表示 //G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;
void Func_F(){LCDDATA0 = 0b01110001;} //F を表示 //G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;
void main (void)
{
TRISCbits.RC1 = 1; // RC1: in //HexSw
TRISG = 0xFF; //G port: in //HexSw
TRISD = 0x00; //D port: out //Segment Data
TRISEbits.RE3 = 0; //COM0: out
TRISHbits.RH0 = 1; //HexSw b0
TRISHbits.RH2 = 0; //LED free run
// LCDCON (LCD CONTROL)レジスタ
LCDCONbits.SLPEN = 0; //Sleep時のLCDドライバーモジュール イネーブル
LCDCONbits.WERR = 0; //No LCD Write Erro //LCD Write Failed Error bit
LCDCONbits.CS1 = 0; //00 Fosc/4 1x INTRC(31KHz) 00 Sys Clock, 01 TMR1 Clk
LCDCONbits.CS0 = 0; //
LCDCONbits.LMUX1 = 0; //00 Static(COM0)スタティック制御 //Commons Select bis
LCDCONbits.LMUX0 = 0;
// LCDPS(LCD PHASE) レジスタ
LCDPSbits.WFT = 0; //0 - TypeA(Phase changes whithin each common type)
LCDPSbits.BIASMD = 0; //Bias Mode Select bit(スタティックモードでは0にセットのこと)
LCDPSbits.LCDA = 0; //LCDドライバモジュールは非アクティブ
LCDPSbits.WA = 0; // LCDへの書き込みは許可されていない。
LCDPSbits.LP3 = 0; //0100LP <3:0> LCDクロックのプリスケーラ 1/5
LCDPSbits.LP2 = 1;
LCDPSbits.LP1 = 0;
LCDPSbits.LP0 = 0;
// LCDSEx (LCD SEGMENT ENABLE)レジスタ
// 1: セグメント機能モード 0: I/Oモード
LCDSE0 = 0xFF; //対応ポート: SEG0-SEG7 //セグメント機能モード
LCDSE1 = 0x00; //対応ポート: SEG8-SEG15//デジタルI/Oモード
LCDSE2 = 0x00; //対応ポート: SEG16-SE23//デジタルI/Oモード
LCDSE3 = 0x00; //対応ポート: SEG24-SEG31//デジタルI/Oモード
LCDSE4 = 0x00; //対応ポート: SEG32-SEG39 //デジタルI/Oモード
LCDSE5 = 0x00; //対応ポート: SEG40-SEG47 //デジタルI/Oモード
// LCDREG(VOLTAGE REGULATOR CONTROL)レジスタ
LCDREGbits.CPEN = 0; //LCDチャージポンプOFF// LCD charge Pump Enable bit
LCDREGbits.CKSEL1 = 0; //Regulator Clock Source Select bit //LCD レギュレータ ディセーブル //
LCDREGbits.CKSEL0 = 0; //
LCDCONbits.LCDEN = 1; //LCDドライバーモジュール イネーブル
while (1)
{
if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 1))Func_0();
else if((b3 == 1) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_1();
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_2();
else if((b3 == 1) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_3();
else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_4();
else if((b3 == 1) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_5();
else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_6();
else if((b3 == 1) && (b2 == 0) && (b1 == 0) && (b0 == 0)) Func_7();
else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 1)) Func_8();
else if((b3 == 0) && (b2 == 1) && (b1 == 1) && (b0 == 0)) Func_9();
else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 1)) Func_A();
else if((b3 == 0) && (b2 == 1) && (b1 == 0) && (b0 == 0)) Func_b();
else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 1)) Func_C();
else if((b3 == 0) && (b2 == 0) && (b1 == 1) && (b0 == 0)) Func_d();
else if((b3 == 0) && (b2 == 0) && (b1 == 0) && (b0 == 1)) Func_E();
else Func_F();
}
}
<動作結果>
HEXスイッチを5に設定した場合の液晶表示の写真です。

■ PIC内蔵ポートによる 液晶セグメントスタティック駆動式 カウンタ
<C18編>
液晶の各セグメントに印加される平均電圧は0vにする必要があります
<試作品仕様>
・液晶コントローラを内蔵しない液晶を スタティック駆動が可能なPICのポートを使って各液晶セグメントを直接制御する
・制御対象は7セグメント液晶1個とする。
・周期1秒の16進カウンタを製作のこと。 また、 Fの次は 0に戻ること
すなわち 0 → 1 → 2 → 3 ……… C → d → E → F → 0 → 1
<試作品回路図>(→回路図のPDFファイル)
PIC18F85J90、液晶:RSコンポーネント(注) RS184-7715の場合の例を示します。
(注) RSコンポーネントは法人でなくとも、個人でも購入できます。 ネットから申し込みの際 法人名の欄に個人と記入すればよいとRSコンポーネントのサポートの方がおしえてくれました。

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

<プログラム例>
/*
1秒毎の 16進Counter値を表示
*/
#include <p18f85J90.h>
#include <stdio.h>
#include <delays.h>
#include <timers.h>
#pragma config FOSC = HS // システムクロック=20MHz
#pragma config XINST = OFF
#pragma config WDTEN = OFF //ウォッチドックタイマ OFF
unsigned long int Count1 = 0;
unsigned long int Count2 = 0;
int LED = 0;
void Func_0(){LCDDATA0 = 0b0111111;} // 0 を表示 //G = 0; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;
void Func_1(){LCDDATA0 = 0b00000110;} // 1 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 0;
void Func_2(){LCDDATA0 = 0b01011011;} // 2 を表示 //G = 1; F = 0; E = 1; D = 1; C = 0; B = 1; A = 1;
void Func_3(){LCDDATA0 = 0b01001111;} //3 を表示 //G = 1; F = 0; E = 0; D = 1; C = 1; B = 1; A = 1;
void Func_4(){LCDDATA0 = 0b01100110;} //4 を表示 //G = 1; F = 1; E = 0; D = 0; C = 1; B = 1; A = 0;
void Func_5(){LCDDATA0 = 0b01101101;} //5 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 0; A = 1;
void Func_6(){LCDDATA0 = 0b01111101;} //6 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 1;
void Func_7(){LCDDATA0 = 0b00000111;} //7 を表示 //G = 0; F = 0; E = 0; D = 0; C = 1; B = 1; A = 1;
void Func_8(){LCDDATA0 = 0b01111111;} //8 を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 1; A = 1;
void Func_9(){LCDDATA0 = 0b01101111;} //9 を表示 //G = 1; F = 1; E = 0; D = 1; C = 1; B = 1; A = 1;
void Func_A(){LCDDATA0 = 0b01110111;} //A を表示 //G = 1; F = 1; E = 1; D = 0; C = 1; B = 1; A = 1;
void Func_b(){LCDDATA0 = 0b01111100;} //b を表示 //G = 1; F = 1; E = 1; D = 1; C = 1; B = 0; A = 0;
void Func_C(){LCDDATA0 = 0b00111001;} //C を表示 //G = 0; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;
void Func_d(){LCDDATA0 = 0b01011110;} //d を表示 //G = 1; F = 0; E = 1; D = 1; C = 1; B = 1; A = 0;
void Func_E(){LCDDATA0 = 0b01111001;} //E を表示 //G = 1; F = 1; E = 1; D = 1; C = 0; B = 0; A = 1;
void Func_F(){LCDDATA0 = 0b01110001;} //F を表示 //G = 1; F = 1; E = 1; D = 0; C = 0; B = 0; A = 1;
#pragma interrupt my_Func // 10msec タイマ1 インターバル割り込み
#pragma code isrcode = 0x08
void isr_direct(void)
{ _asm goto my_Func _endasm }
#pragma code
void my_Func(void)
{
PIR1bits.TMR1IF = 0; // タイマ1割り込みフラグをクリアする
WriteTimer1(59286); // 0.05μsec × 4 × 8 × 6250 = 10000μsec = 10msec (at システムクロック20MHz)
// 256×256 - 6250 = 59286
// タイマ0:16bitアップカウントタイマ → オーバーフローで割込み発生
Count1++;
if(Count1 >= 100) //1秒毎に
{
Count1 = 0;
if(Count2 == 0)Func_0();
else if(Count2 == 1) Func_1();
else if(Count2 == 2) Func_2();
else if(Count2 == 3) Func_3();
else if(Count2 == 4) Func_4();
else if(Count2 == 5) Func_5();
else if(Count2 == 6) Func_6();
else if(Count2 == 7) Func_7();
else if(Count2 == 8) Func_8();
else if(Count2 == 9) Func_9();
else if(Count2 == 10) Func_A();
else if(Count2 == 11) Func_b();
else if(Count2 == 12) Func_C();
else if(Count2 == 13) Func_d();
else if(Count2 == 14) Func_E();
else Func_F();
Count2++;
if(Count2 >= 16)Count2 = 0;
if(LED == 1)
{
PORTDbits.RD1 = 0; // RD1 LED ON
LED = 0;
}
else
{
PORTDbits.RD1 = 1; // BポートのLED OFF
LED = 1;
}
}
}
void main (void)
{
TRISCbits.RC1 = 1; // RC1: in //HexSw
TRISG = 0xFF; //G port: in //HexSw
TRISD = 0x00; //D port: out //Segment Data
TRISEbits.RE3 = 0; //COM0: out
TRISHbits.RH0 = 1; //HexSw b0
TRISHbits.RH2 = 0; //LED free run
// LCDCON (LCD CONTROL)レジスタ
LCDCONbits.SLPEN = 0; //Sleep時のLCDドライバーモジュール イネーブル
LCDCONbits.WERR = 0; //No LCD Write Erro //LCD Write Failed Error bit
LCDCONbits.CS1 = 0; //00 Fosc/4 1x INTRC(31KHz) 00 Sys Clock, 01 TMR1 Clk
LCDCONbits.CS0 = 0; //
LCDCONbits.LMUX1 = 0; //00 Static(COM0)スタティック制御 //Commons Select bis
LCDCONbits.LMUX0 = 0;
// LCDPS(LCD PHASE) レジスタ
LCDPSbits.WFT = 0; //0 - TypeA(Phase changes whithin each common type)
LCDPSbits.BIASMD = 0; //Bias Mode Select bit(スタティックモードでは0にセットのこと)
LCDPSbits.LCDA = 0; //LCDドライバモジュールは非アクティブ
LCDPSbits.WA = 0; // LCDへの書き込みは許可されていない。
LCDPSbits.LP3 = 0; //0100LP <3:0> LCDクロックのプリスケーラ 1/5
LCDPSbits.LP2 = 1; //31000Hz / 5 = 6200Hz
LCDPSbits.LP1 = 0;
LCDPSbits.LP0 = 0;
// LCDSEx (LCD SEGMENT ENABLE)レジスタ
// 1: セグメント機能モード 0: I/Oモード
LCDSE0 = 0xFF; //対応ポート: SEG0-SEG7 //セグメント機能モード
LCDSE1 = 0x00; //対応ポート: SEG8-SEG15//デジタルI/Oモード
LCDSE2 = 0x00; //対応ポート: SEG16-SE23//デジタルI/Oモード
LCDSE3 = 0x00; //対応ポート: SEG24-SEG31//デジタルI/Oモード
LCDSE4 = 0x00; //対応ポート: SEG32-SEG39 //デジタルI/Oモード
LCDSE5 = 0x00; //対応ポート: SEG40-SEG47 //デジタルI/Oモード
// LCDREG(VOLTAGE REGULATOR CONTROL)レジスタ
LCDREGbits.CPEN = 0; //LCDチャージポンプOFF// LCD charge Pump Enable bit
LCDREGbits.CKSEL1 = 0; //Regulator Clock Source Select bit //LCD レギュレータ ディセーブル //
LCDREGbits.CKSEL0 = 0; //
LCDCONbits.LCDEN = 1; //LCDドライバーモジュール イネーブル
//タイマ1の設定
OpenTimer1
(
TIMER_INT_ON & //割込み:ON
T1_16BIT_RW & //16 bit モードに設定 vs 8bit モード( T0_8BIT )
T1_SOURCE_INT & //内部クロック使用
T1_PS_1_8 & //8ビットプリスケーラ 1/8 vs 1/1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256
T1_OSC1EN_OFF
);
WriteTimer1(59286);
RCONbits.IPEN = 0; //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0)
PIE1bits.TMR1IE = 1; //タイマ1割込み許可
INTCONbits.PEIE =1; //周辺割込み許可
//INTCONレジスタの b6ビット : 低位割込み許可/禁止(割り込み優先順位制御 有りの場合)
INTCONbits.GIE = 1; //全割込み許可
//INTCONレジスタの b7ビット : 高位割込み許可/禁止(割り込み優先順位制御 有りの場合)
while (1)
{
}
}
<動作結果>
カウンタ値が3の場合の写真です。
